package com;

/**
 * Rendre le serveur JBoss accessible depuis le telephone : 
 * double click sur le serveur,
 * Open Launch Configuration
 * dans programs arguments : ajouter -b 0.0.0.0 
 */

import java.io.IOException;
import java.io.PrintStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import arbre.utils.ArbreBinaire;
import arbre.utils.ContentNode;
import arbre.utils.Noeud;

import com.graphe.INoeud;
import com.graphe.Segment;
import com.xml.MapXmlParser;

import org.codehaus.jackson.map.ObjectMapper;


/**
 * Servlet implementation class Graphe
 */
@WebServlet({ "/Graphe", "/chemin", "/requete", "/demande", "/struts", "/", "/Localisation", "/localisation", "/spring", "/arbre" })
public class Graphe extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private String SESSION_MAP = "MAP";
	private String SESSION_BATIMENT = "BATIMENT";

	private String PARAMETRE_SOURCE = "source";
	private String PARAMETRE_DESTINATION = "destination";
	private String PARAMETRE_BATIMENT = "batiment";
	private String PARAMETRE_GRAPHE = "graphe";
	private String PARAMETRE_VERSION = "version";

	private static final String VERSION = "1.0.1";
	
	static ArbreBinaire arbrePolyedres = null;
	static ArbreBinaire arbreChemins = null;

	private String SESSION_ARBRE_POLYEDRES = "SESSION_ARBRE_POLYEDRES";
	private String SESSION_ARBRE_CHEMINS = "SESSION_ARBRE_CHEMINS";

	private String PARAMETRE_X = "x";
	private String PARAMETRE_Y = "y";

	public Graphe() {
		super();
	}



	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession(true);  
		
		com.graphe.Graphe map = (com.graphe.Graphe)session.getAttribute(SESSION_MAP);
		com.graphe.Graphe batiment = (com.graphe.Graphe)session.getAttribute(SESSION_BATIMENT);
		if(map == null || batiment == null){
			map = chargerMap();
			batiment = chargerBatiment();

			session.setAttribute(SESSION_MAP, map);
			session.setAttribute(SESSION_BATIMENT, batiment);
		}
		
//		arbrePolyedres = (ArbreBinaire)session.getAttribute(SESSION_ARBRE_POLYEDRES);
//		arbreChemins = (ArbreBinaire)session.getAttribute(SESSION_ARBRE_CHEMINS);
//		if(arbrePolyedres == null){
//			response.getOutputStream().print("chargement des arbres");
			chargerArbres(response);
//			
//			session.setAttribute(SESSION_ARBRE_POLYEDRES, arbrePolyedres);
//			session.setAttribute(SESSION_ARBRE_CHEMINS, arbreChemins);
//		}
//		else{
//			response.getOutputStream().print("deja chargé \n");
//		}
		
		String source = (String)request.getParameter(PARAMETRE_SOURCE);
		String destination = (String)request.getParameter(PARAMETRE_DESTINATION);
		String isBatiment = (String)request.getParameter(PARAMETRE_BATIMENT);
		String getGraphe = (String)request.getParameter(PARAMETRE_GRAPHE);
		String getVersion = (String)request.getParameter(PARAMETRE_VERSION);
		
		String sx = (String)request.getParameter(PARAMETRE_X);
		String sy = (String)request.getParameter(PARAMETRE_Y);

		INoeud noeudSource = null;
		INoeud noeudDest = null;

		com.graphe.Graphe graphe = map;
		if(isBatiment != null){
			System.out.println("recherche dans batiment");
			graphe = batiment;
		}

		if(getGraphe != null){
			ObjectMapper mapper = new ObjectMapper();
			mapper.writeValue(response.getOutputStream(), graphe);
		}
		else if(getVersion != null){
			response.getOutputStream().print(VERSION);
		}
		else if(sx != null && sy != null){
			
			//response.getOutputStream().print(sx+" "+sy);
			
			try{
				Float x = Float.valueOf(sx);
				Float y = Float.valueOf(sy);
				
				System.out.println("recherche x="+x+" y="+y);

				com.graphe.Point p = new com.graphe.Point(x,y);

				ContentNode node = localiser(p,graphe,response);

				ObjectMapper mapper = new ObjectMapper();
				mapper.writeValue(response.getOutputStream(), node);

			}catch(Exception e){
				e.printStackTrace(new PrintStream(response.getOutputStream()));
			}
		}
		else{

			noeudSource = trouverINoeud(graphe,source);
			noeudDest = trouverINoeud(graphe,destination);

			System.out.println("charge");

			if(noeudSource != null && noeudDest != null){
				System.out.println("recherche du chemin");
				List<INoeud> chemin = graphe.plusCourtChemin(noeudSource, noeudDest);
				ObjectMapper mapper = new ObjectMapper();
				mapper.writeValue(response.getOutputStream(), chemin);

			}
			System.out.println("finit");
		}


	}

	protected INoeud trouverINoeud(com.graphe.Graphe graphe, String id){
		if(graphe.getChemins().containsKey(id))
			return graphe.getChemins().get(id);
		else if(graphe.getPolygones().containsKey(id))
			return graphe.getChemins().get(id);
		else
			return null;
	}

	protected com.graphe.Graphe chargerGraphe(String nom){
		String xml = LecteurFichier.readFile(this,nom);

		MapXmlParser parseur = new  MapXmlParser(xml);
		return parseur.getMap();
	}

	protected com.graphe.Graphe chargerMap(){
		return chargerGraphe("map.xml");
	}
	protected com.graphe.Graphe chargerBatiment(){
		return chargerGraphe("batiment.xml");
	}	
	
	private static final String POLYGON_TREE_PATH="arbrePolygon.json";
	private static final String CHEMIN_TREE_PATH="arbreChemin.json";

	private void chargerArbres(HttpServletResponse response) {

		System.out.println("Charger des arbres");
		ObjectMapper mapper = new ObjectMapper();

		try{
			String polyJSon = LecteurFichier.readFile(this, POLYGON_TREE_PATH);
			String cheminJson = LecteurFichier.readFile(this, CHEMIN_TREE_PATH);
			
			ArbreBinaire ar = mapper.readValue(polyJSon, ArbreBinaire.class);
			System.out.println("Lecture de l'arbre de localisation dans les polygones");
			
			arbrePolyedres = new ArbreBinaire();
			
			arbrePolyedres.setRacine(ar.getRacine());

			ArbreBinaire ar2 = mapper.readValue(cheminJson, ArbreBinaire.class);
			System.out.println("Lecture de l'arbre de localisation dans les chemins");
			
			arbreChemins = new ArbreBinaire();
			
			arbreChemins.setRacine(ar2.getRacine());

		}catch(Exception e){
			try {
				e.printStackTrace(new PrintStream(response.getOutputStream()));
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}

		System.out.println("Arbres chargés");
	}

	public ContentNode localiser(com.graphe.Point p, com.graphe.Graphe graphe, HttpServletResponse response){
		ContentNode res = null;
		res = localiserChemin(arbreChemins.getRacine(),p, graphe);
		
		if(res == null || res.getId().equalsIgnoreCase("DEFAULT")){
			try {
				response.getOutputStream().print("Pas de chemin, on passe aux polygons");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			res = localiserPolygon(arbrePolyedres.getRacine(),p,graphe);
			res.setT("poly");
			return res;
		}else{
			res.setT("chemin");
			return res;	
		}
	}

	private ContentNode localiserPolygon(Noeud n,com.graphe.Point p, com.graphe.Graphe graphe) {
		//verticale
		if(n.getC().getT().equals("v")){
			if(p.getX() <= n.getC().getA()){
				return localiserPolygon(n.getL(), p, graphe);
			}
			else{
				return localiserPolygon(n.getR(), p, graphe);
			}
		}
		//segment
		else if(n.getC().getT().equals("s")){
			int rank = Integer.parseInt(n.getC().getId().substring(n.getC().getId().lastIndexOf("_")+1));
			String segID = n.getC().getId().substring(0, n.getC().getId().lastIndexOf("_"));
			Segment s= new Segment(segID, graphe.getPolygones().get(segID).getPoly().get(rank), graphe.getPolygones().get(segID).getPoly().get(rank+1));
			if(s.dessous(p)){
				return localiserPolygon(n.getL(), p, graphe);
			}else if(s.dessus(p)){
				return localiserPolygon(n.getR(), p, graphe);
			}else{
				return new ContentNode("poly",segID,-100000f,null,null);
			}
		}
		else if(n.getC().getT().equals("z")){
			return n.getC();
		}
		return null;
	}

	private ContentNode localiserChemin(Noeud n,com.graphe.Point p,com.graphe.Graphe graphe) {
		if(n.getC().getT().equals("v")){
			//verticale
			if(p.getX()<= n.getC().getA()){
				return localiserChemin(n.getL(), p,graphe);
			}
			else{
				return localiserChemin(n.getR(), p,graphe);
			}
		}
		else if(n.getC().getT().equals("s")){
			// l'id du segment est n.getC.getId()
			Segment s = graphe.getChemins().get(n.getC().getId());
			if(s.dessous(p)){
				return localiserChemin(n.getL(), p,graphe);
			}
			if(s.dessus(p)){
				return localiserChemin(n.getR(), p,graphe);
			}
			//sur
			return n.getC();
		}
		else if(n.getC().getT().equals("z")){
			return n.getC();
		}
		return null;
	}

}
